import { ValueT } from '@/type';
import TranstionList from '@/utils/TransitionList';
import WatchNumber from '@/utils/WatchNumber';
import { SplitLineInfo } from '../type';
import Visual from '../Visual';
import StringView from '../view/StringView';
import LineView from '../view/LineView';

/** 分割线控制系统 */
export default class SplitUtils {

	/** 可视化控制类 */
	private visual: Visual;

	/** 分割线信息数组 */
	public splitInfoSet!: Map<number, SplitLineInfo>;

	/** 分割线过渡列表 */
	public splitTransition!: TranstionList<number>;

	/** 还需要绘制 */
	public get HasNext(): boolean {
		return Array.from(this.splitInfoSet).some(info => info[1].transparency.HasNext);
	}

	/**
	 * 构造函数
	 * @param visual 可视化控制类
	 */
	public constructor(visual: Visual) {
		this.visual = visual;
		this.splitInfoSet = new Map();
		this.splitTransition = new TranstionList();
	}

	/** 重置 */
	public Load() {
		this.splitInfoSet.clear();
		this.splitTransition.Clear();
	}

	/** 更新数据 */
	public LoadingData() {
		const { visual, splitInfoSet, splitTransition } = this;
		const { dataUtils, configUtils } = visual;
		const { drawReadData } = dataUtils;
		const { minValue, maxValue } = drawReadData.saveData;
		const splitList = configUtils.CalcSplitLine(minValue, maxValue);
		splitTransition.Push(splitList);
		splitTransition.Enter.map(value => {
			const findInfo = splitInfoSet.get(value);
			if (findInfo) {
				findInfo.state = "update";
				findInfo.transparency.Value = 1;
			} else {
				const info = this.MakeSplitLineInfo(value);
				splitInfoSet.set(value, info);
				info.state = "update";
				info.transparency.Value = 1;
				info.x.Value = this.CalcInfoLastX(info.value);
			}
		});
		splitTransition.Remove.map(value => {
			const info = splitInfoSet.get(value);
			if (info) {
				info.state = "remove";
				info.transparency.Value = 0;
			}
		});
		splitInfoSet.forEach((info) => {
			this.CalcInfoX(info);
		});
	}

	private CalcInfoLastX(value: number): number {
		const { visual } = this;
		const { configUtils, dataUtils } = visual;
		const { drawReadData, drawOldData } = dataUtils;
		if (drawOldData) {
			const { maxValue, minValue } = drawOldData;
			return configUtils.CalcAxisWidth(minValue, maxValue, value);
		} else {
			const { saveData } = drawReadData;
			const { maxValue, minValue } = saveData;
			return configUtils.CalcAxisWidth(minValue, maxValue, value);
		}
	}

	private CalcInfoX(info: SplitLineInfo) {
		const { visual } = this;
		const { configUtils, dataUtils } = visual;
		const { drawReadData } = dataUtils;
		const { saveData } = drawReadData;
		const { maxValue, minValue } = saveData;
		const value = info.value;
		info.x.Value = configUtils.CalcAxisWidth(minValue, maxValue, value);
	}

	/** 创建分割线绘制项 */
	private MakeSplitLineInfo(value: number): SplitLineInfo {
		const { visual, splitInfoSet } = this;
		const { viewUtils, configUtils } = visual;
		const { Block } = viewUtils;
		const rectBox = Block.QuerySelector("rectBox");
		const { Content: { Left, Width } } = rectBox;
		const x = configUtils.makeValueTranstion(this.CalcInfoLastX(value));
		const transparency = configUtils.makeSplitLineTranstion(0);
		const calcX = new WatchNumber((num, x, width) => x.Value + num.Value * width.Value, x.Watch, Left, Width);
		const splitValue = this.MakeSplitValue(value, calcX, transparency);
		const splitLine = this.MakeSplitLine(calcX, transparency);
		viewUtils.Add(splitValue);
		viewUtils.Add(splitLine);
		const state = "remove";
		const remove = () => {
			viewUtils.Delete(splitValue);
			viewUtils.Delete(splitLine);
			splitInfoSet.delete(value);
		};
		return { value, state, x, transparency, remove };
	}

	private MakeSplitValue(value: number, x: ValueT<number>, transparency: ValueT<number>) {
		const { visual } = this;
		const { canvas, viewUtils, configUtils } = visual;
		const { Block } = viewUtils;
		const { splitValueColor } = configUtils.config;
		const splitValueBox = Block.QuerySelector("splitValueBox");
		const { Content: { Top: y, Height: size } } = splitValueBox;
		const content = configUtils.makeFormatSplitValueWatch(value);
		const color = splitValueColor;
		const baseLine: ValueT<CanvasTextBaseline> = { Value: "top" };
		const textAlign: ValueT<CanvasTextAlign> = { Value: "center" };
		return new StringView(canvas, { x, y, content, size, color, borderColor: color, baseLine, textAlign, transparency });
	}

	private MakeSplitLine(x: ValueT<number>, transparency: ValueT<number>) {
		const { visual } = this;
		const { canvas, viewUtils, configUtils } = visual;
		const { Block } = viewUtils;
		const { splitLineColor, splitLineWidth } = configUtils.config;
		const main = Block.QuerySelector("main");
		const { Content: { Top, Height } } = main;
		const bY = new WatchNumber((y, height) => y.Value + height.Value, Top, Height);
		const color = splitLineColor;
		const lineWidth = splitLineWidth;
		const lineCap: ValueT<CanvasLineCap> = { Value: "round" };
		return new LineView(canvas, { aX: x, aY: Top, bX: x, bY, color, transparency, lineWidth, lineCap });
	}

	/** 绘制之前 */
	public BeforeDraw() {
		const { splitInfoSet } = this;
		splitInfoSet.forEach(info => {
			info.x.Trigger();
			info.transparency.Trigger();
			if (info.transparency.Value === 0 && info.state === "remove") {
				info.remove();
			}
		});
	}
}
